/*
 * @brief Sensor Hub demo menu (implementation file)
 *
 * @note
 * Copyright(C) NXP Semiconductors, 2015
 * All rights reserved.
 *
 * @par
 * Software that is described herein is for illustrative purposes only
 * which provides customers with programming information regarding the
 * LPC products.  This software is supplied "AS IS" without any warranties of
 * any kind, and NXP Semiconductors and its licensor disclaim any and
 * all warranties, express or implied, including all implied warranties of
 * merchantability, fitness for a particular purpose and non-infringement of
 * intellectual property rights.  NXP Semiconductors assumes no responsibility
 * or liability for the use of the software, conveys no license or rights under any
 * patent, copyright, mask work right, or any other intellectual property rights in
 * or to any products. NXP Semiconductors reserves the right to make changes
 * in the software without notification. NXP Semiconductors also makes no
 * representation or warranty that such application will be suitable for the
 * specified use without further testing or modification.
 *
 * @par
 * Permission to use, copy, modify, and distribute this software and its
 * documentation is hereby granted, under NXP Semiconductors' and its
 * licensor's relevant copyrights in the software, without fee, provided that it
 * is used in conjunction with NXP Semiconductors microcontrollers.  This
 * copyright, permission, and disclaimer notice must appear in all copies of
 * this code.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

#include "hostif_protocol.h"

#include "trace.h"
#include "gl_text.h"
#include "teapot.h"
#include "recorder.h"
#include "sensorhal.h"
#include "auto_rotate.h"

#include "gl_menu.h"

/*****************************************************************************
 * Public types/enumerations/variables
 ****************************************************************************/

/*****************************************************************************
 * Private types/enumerations/variables
 ****************************************************************************/
typedef struct {
	char*	menu_name;
	int		menu_id;
} MENU_ENTRY;

static	bool 		hud;														/* Heads-up display (HUD) flag: true=HUD is up */
static	bool 		timestamp;													/* Timestamp flag: false = raw / true = h:m:s */
static	uint32_t	disp	= 0;												/* menu display item: what is in the HUD */
static	uint32_t	dev		= 0;												/* menu device item: what device is active */

static MENU_ENTRY sub_menu[] = {
	{ "Accelerometer",					DISP_ACCELEROMETER					},	/* add Accelerometer */
	{ "Uncalibrated Accelerometer",		DISP_ACCELEROMETER_UNCALIBRATED		},	/* add Uncalibrated Accelerometer */
	{ "Magnetometer",					DISP_MAGNETIC_FIELD					},	/* add Magnetic Sensor */
	{ "Uncalibrated Magnetic Sensor",	DISP_MAGNETIC_FIELD_UNCALIBRATED	},	/* add Uncalibrated Magnetic Sensor */
	{ "Gyroscope",						DISP_GYROSCOPE						},	/* add Gyroscope */
	{ "Uncalibrated Gyroscope",			DISP_GYROSCOPE_UNCALIBRATED			},	/* add Uncalibrated Gyroscope */
	{ "Light",							DISP_LIGHT							},	/* add Light Sensor */
	{ "Pressure / Temperature",			DISP_PRESSURE						},	/* add Pressure Sensor */
	{ "Proximity",						DISP_PROXIMITY						},	/* add Proximity Sensor */
	{ "Rotation Vector",				DISP_ROTATION_VECTOR				}	/* add Rotation Vector */
};

static MENU_ENTRY main_menu[] = {
	{ "Display HUD",					MENU_ITEM_HUD				},			/* add HUD control */
	{ "Update Offset",					MENU_ITEM_UPDATE_OFFSET		},			/* add update offset */
	{ "All Sensors",					MENU_ITEM_All_ON			},			/* all sensors on */
	{ "Sensor Reset",					MENU_ITEM_SENSOR_RESET		},			/* add sensor reset */
	{ "Quit",							MENU_ITEM_QUIT				}			/* add program exit */
};


/*
--------------------------------------------------------------------------------
	Private functions
--------------------------------------------------------------------------------
 */

/*
--------------------------------------------------------------------------------
	Private functions
	Enable all sensors: This function goes through the sensor_tab and enables
	all sensors.

	Note: 	LPCSH_SENSOR_ID_ROTATION_VECTOR is always enabled.
--------------------------------------------------------------------------------
 */
static uint8_t sensor_tab[] =
{
	LPCSH_SENSOR_ID_ACCELEROMETER,
	LPCSH_SENSOR_ID_ACCELEROMETER_UNCALIBRATED,
	LPCSH_SENSOR_ID_MAGNETIC_FIELD,
	LPCSH_SENSOR_ID_MAGNETIC_FIELD_UNCALIBRATED,
	LPCSH_SENSOR_ID_GYROSCOPE,
	LPCSH_SENSOR_ID_GYROSCOPE_UNCALIBRATED,
	LPCSH_SENSOR_ID_LIGHT,
	LPCSH_SENSOR_ID_PRESSURE,
	LPCSH_SENSOR_ID_PROXIMITY
};
static uint32_t sensor_tab_ct = sizeof(sensor_tab) / sizeof(uint8_t);
static void all_on(void)
{
	uint32_t i;

	if (auto_rotate_get() == true) return;										/* if auto-rotate is enabled, do not add sensors */

	for (i=0; i<sensor_tab_ct; i++) {											/* go through all the sensors in the table */
		sensor_hal_enable(sensor_tab[i], true);									/* enable the sensor */
		Sleep(10);																/* wait 10ms */
	}
	if (sensor_hal_get_no_sensors() == true) {									/* if no sensors are enabled at start, then start the rotation vector */
		sensor_hal_enable(LPCSH_SENSOR_ID_ROTATION_VECTOR, true);				/* enable the sensor */
	}
	disp = 0xfff;																/* display everything */
}

static void s_enable(uint32_t disp_item, uint32_t device)
{
	bool en_flag = (disp & disp_item) ? true : false;
	sensor_hal_enable(device, en_flag);
}

static void display_menu_callback(int item)
{
	if (auto_rotate_get() == true) return;

	switch (item) {
	case DISP_ACCELEROMETER:
		disp ^= DISP_ACCELEROMETER;
		s_enable(DISP_ACCELEROMETER, LPCSH_SENSOR_ID_ACCELEROMETER);
		break;
	case DISP_ACCELEROMETER_UNCALIBRATED:
		disp ^= DISP_ACCELEROMETER_UNCALIBRATED;
		s_enable(DISP_ACCELEROMETER_UNCALIBRATED, LPCSH_SENSOR_ID_ACCELEROMETER_UNCALIBRATED);
		break;
	case DISP_MAGNETIC_FIELD:
		disp ^= DISP_MAGNETIC_FIELD;
		s_enable(DISP_MAGNETIC_FIELD, LPCSH_SENSOR_ID_MAGNETIC_FIELD);
		break;
	case DISP_MAGNETIC_FIELD_UNCALIBRATED:
		disp ^= DISP_MAGNETIC_FIELD_UNCALIBRATED;
		s_enable(DISP_MAGNETIC_FIELD_UNCALIBRATED, LPCSH_SENSOR_ID_MAGNETIC_FIELD_UNCALIBRATED);
		break;
	case DISP_GYROSCOPE:
		disp ^= DISP_GYROSCOPE;
		s_enable(DISP_GYROSCOPE, LPCSH_SENSOR_ID_GYROSCOPE);;
		break;
	case DISP_GYROSCOPE_UNCALIBRATED:
		disp ^= DISP_GYROSCOPE_UNCALIBRATED;
		s_enable(DISP_GYROSCOPE_UNCALIBRATED, LPCSH_SENSOR_ID_GYROSCOPE_UNCALIBRATED);
		break;
	case DISP_LIGHT:
		disp ^= DISP_LIGHT;
		s_enable(DISP_LIGHT, LPCSH_SENSOR_ID_LIGHT);
		break;
	case DISP_PRESSURE:
		disp ^= DISP_PRESSURE;
		s_enable(DISP_PRESSURE, LPCSH_SENSOR_ID_PRESSURE);
		break;
	case DISP_PROXIMITY:
		disp ^= DISP_PROXIMITY;
		s_enable(DISP_PROXIMITY, LPCSH_SENSOR_ID_PROXIMITY);
		break;
	case DISP_ROTATION_VECTOR:
		disp ^= DISP_ROTATION_VECTOR;
		if (sensor_hal_get_no_sensors() == true) {									/* if no sensors are enabled at start, then start the rotation vector */
			s_enable(DISP_ROTATION_VECTOR, LPCSH_SENSOR_ID_ROTATION_VECTOR);		/* enable / disable the sensor */
		}
		break;
	default:
		disp = DISP_NONE;
		trace(TRACE_INFO,"unknown menu item: %d.",item);
		break;
	}

	trace(TRACE_INFO, "display: %08x",disp);
	glutPostRedisplay();
}

static void main_menu_callback(int item)
{
	switch (item) {
	case MENU_ITEM_HUD:
		hud = (hud == true) ? false : true;
		break;

	case MENU_ITEM_UPDATE_OFFSET:
		teapot_update_offset();
		break;

	case MENU_ITEM_SENSOR_RESET:
		sensor_hal_hub_reset();
		gl_menu_init();
		break;

	case MENU_ITEM_All_ON:
		all_on();
		break;

	case MENU_ITEM_QUIT:
		sensor_hal_exit();
		rec_stop();
		exit(1);
		break;

	default:
		trace(TRACE_INFO, "unknown menu item: %d.",item);
		break;
	}
	glutPostRedisplay();
}

static void key_callback(unsigned char key, int x, int y)
{
	switch (key) {
	case 'a':
		all_on();
		break;

	case 'r':
		sensor_hal_hub_reset();
		gl_menu_init();
		break;

	case 'h':
		hud = (hud == true) ? false : true;
		break;

	case 't':
		timestamp = (timestamp == true) ? false : true;
		break;

	case 27: /* escape key */
	case 'q':
	case 'x':
		sensor_hal_exit();
		rec_stop();
		exit(1);
		break;

	case 's':
		teapot_update_offset();
		break;
	}
}

/*****************************************************************************
 * Public functions
 ****************************************************************************/

void gl_menu_init(void)
{
	hud = true;
	timestamp = true;
	disp = DISP_NONE;
	dev = LPCSH_SENSOR_ID_ROTATION_VECTOR;
}

void gl_menu_create(void)
{
	int display_m;
	int i;

	glutKeyboardFunc(key_callback);												/* register callback for keyboard input */
	display_m = glutCreateMenu(display_menu_callback);							/* create display sub-menu and register callback */
	for (i=0; i<12; i++)
		glutAddMenuEntry(sub_menu[i].menu_name, sub_menu[i].menu_id);			/* add Accelerometer */

	glutCreateMenu(main_menu_callback);											/* create main menu and register callback */
	glutAddSubMenu("Display", display_m);										/* add display sub-menu */
	for (i=0; i<5; i++)
		glutAddMenuEntry(main_menu[i].menu_name, main_menu[i].menu_id);			/* add Accelerometer */
	glutAttachMenu(GLUT_RIGHT_BUTTON);											/* attach to the right button */
}

bool gl_menu_ts_get(void)
{
	return timestamp;
}

bool gl_menu_hud_get(void)
{
	return hud;
}

uint32_t gl_menu_disp_get(void)
{
	return disp;
}
